package spe.ui.editor.command;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.gef.commands.Command;

import spe.model.notation.Link;
import spe.model.notation.SPEMDiagram;
import spe.model.spem.MethodContentPackage;
import spe.model.spem.MethodPlugin;
import spe.model.spem.NodeElement;
import spe.model.spem.PackageElement;
import spe.model.spem.ProcessPackage;
import spe.model.spem.RoleDefinition;
import spe.model.spem.SPEMElement;
import spe.model.spem.TaskDefinition;

public class ElementDeleteCommand extends Command 
{
	private NodeElement element;
	private SPEMDiagram diagram;
	
	private List<ElementDeleteCommand> childNodeDeleteCommands = null;
	private List<LinkDeleteCommand> linkDeleteCommands = null;
	
	@Override
	public void execute()
	{
		//System.out.println(String.format("[ElementDeleteCommand] Command %s,  Element %s", this, element));
		if(childNodeDeleteCommands == null)
			createChildNodeDeleteCommands();
		
		for(LinkDeleteCommand cmd: linkDeleteCommands)
			cmd.execute();
		
		for(ElementDeleteCommand cmd: childNodeDeleteCommands)
			cmd.execute();
		
		doDelete();
	}
	
	private void createChildNodeDeleteCommands()
	{		
		List<SPEMElement> children;
		ElementDeleteCommand cmd;
		LinkDeleteCommand linkCmd;
		
		childNodeDeleteCommands = new ArrayList<ElementDeleteCommand>();
		linkDeleteCommands = new ArrayList<LinkDeleteCommand>();
		
		if(element instanceof PackageElement)
		{
			PackageElement e = (PackageElement)element;
			children = e.getChildElements();//Dangerous!!!!!!!
			
			for(SPEMElement child: children)
			{
				cmd = new ElementDeleteCommand();
				//System.out.println(String.format("[ElementDeleteCommand] Command %s,  Element %s", cmd, child));
				cmd.setElement((NodeElement) child);
				childNodeDeleteCommands.add(cmd);
			}
		}
		
		List<Link> outlinks = element.getLeavingEdges(); // getOutgoingLinks();
		List<Link> inlinks = element.getArrivingEdges(); // getIncomingLinks();
		
		for(Link l: outlinks)
		{
			linkCmd = new LinkDeleteCommand();
			linkCmd.setLink(l);
			//linkCmd.setDiagram(diagram);
			linkDeleteCommands.add(linkCmd);
		}
		
		for(Link l: inlinks)
		{
			linkCmd = new LinkDeleteCommand();
			linkCmd.setLink(l);
			//linkCmd.setDiagram(diagram);
			linkDeleteCommands.add(linkCmd);
		}
	}
	
	/*
	 * To delete an element, we remove it from its parent all relationship to or from it
	 * 
	 * */
	private void doDelete()
	{
		//NodeElement parent = element.getParent();
		List<Link> outlinks = element.getLeavingEdges(); //getOutgoingLinks();
		List<Link> inlinks = element.getArrivingEdges(); //getIncomingLinks();
		
		NodeElement obj;
		for(Link l: outlinks)
		{
			obj = (NodeElement)(l.getTarget());
			element.removeLeavingEdge(l);
			obj.removeArrivingEdge(l);
		}
		
		for(Link l: inlinks)
		{
			obj = (NodeElement)(l.getSource());
			element.removeArrivingEdge(l);
			obj.removeLeavingEdge(l);
		}
		
		if(element instanceof RoleDefinition)
		{
			//((RoleDefinition)element
		}
		else if(element instanceof TaskDefinition)
		{
			((TaskDefinition)element).setAdditionalPerformers(null);
			((TaskDefinition)element).setParameters(null);
		}
		else if(element instanceof MethodPlugin)
		{
			((MethodPlugin)element).getOwnedMethodContentPackages().clear();
			((MethodPlugin)element).getOwnedProcessPackages().clear();
			((MethodPlugin)element).setBasePlugin(null);	
		}
		else if(element instanceof MethodContentPackage)
		{
			((MethodContentPackage)element).setOwnedMembers(null);
			MethodPlugin parent = (MethodPlugin)element.getParent();
			if(parent != null)
				parent.removeMethodContentPackage((MethodContentPackage)element);
		}
		else if(element instanceof ProcessPackage)
		{
			((ProcessPackage)element).setOwnedMembers(null);
			MethodPlugin parent = (MethodPlugin)element.getParent();
			if(parent != null)
				parent.removeProcessPackage((ProcessPackage)element);
		}
		
		diagram.removeElement(element);
		element.setParent(null);
		//element.setAdapters(null);
	}
	
	public void setElement(NodeElement e)
	{
		this.element = e;
		this.diagram = element.getContainer();
		//System.out.println(String.format("[ElementDeleteCommand] Diagram %s,  Element %s", diagram, e));
	}
}
